home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 3
/
Cream of the Crop 3.iso
/
comm
/
wnos5src.zip
/
MAILBOX.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-10-04
|
37KB
|
1,585 lines
/* There are only two functions in this mailbox code that depend on the
* underlying protocol, namely mbx_getname() and dochat(). All the other
* functions can hopefully be used without modification on other stream
* oriented protocols than AX.25 or NET/ROM.
*
* SM0RGV 890506, most work done previously by W9NK
*
*** Changed 900114 by KA9Q to use newline mapping features in stream socket
* interface code; everything here uses C eol convention (\n)
*
* Numerous new commands and other changes by SM0RGV, 900120
*/
#include <stdio.h>
#include <time.h>
#include <ctype.h>
#include <io.h>
#include "global.h"
#include "config.h"
#include "timer.h"
#include "mailbox.h"
#include "cmdparse.h"
#include "proc.h"
#include "socket.h"
#include "usock.h"
#include "session.h"
#include "ax25.h"
#include "bbs.h"
#include "dirutil.h"
#include "telnet.h"
#include "netrom.h"
#include "commands.h"
#include "netuser.h"
#include "files.h"
#include "server.h"
#ifdef MODEM
#include "modem.h"
#endif
#define MAX_MBXERR 3 /* a try to stop endless "Huh?" or "Error ?" */
#define RETR_CMD 9
#define STOR_CMD 10
struct mbx *Mbox = NULLMBX;
#undef UK
#ifdef UK
int ThirdParty = 1; /* default to thirdparty mail allowed */
#endif
static char Banner[] = "[WNOS-H$]\n";
static char Noperm[] = "Permission denied\n";
static char MHostname[30] = "\0";
static char MBHostname[30] = "\0";
static char MMotd[120] = "\0";
static char Mbbanner[] = "%s%s TCP/IP system.";
static char number[7];
static char Loginbanner[] = "\nWNOS (%s)\n";
static char Howtoend[] = "Terminate with /EX or ^Z in first column (^A aborts)\n";
static char Aborted[] = "*** aborted\n";
#ifdef NETROM
static char mbnrid[20] = "\0";
#endif
#if (!defined(AX25) || defined(NETROM))
static char Noserv[] = "Service unavailable\n";
#endif
static void gw_alarm __ARGS((void *p));
static int near mbx_getname __ARGS((struct mbx *m));
static int near gw_connect __ARGS((struct mbx *m,int s,char *fsocket,int len));
static void gw_input __ARGS((int s,void *notused,void *p));
static void gw_superv __ARGS((int null,void *proc,void *p));
static int near mbx_parse __ARGS((struct mbx *m));
static int domboxbye __ARGS((int argc,char **argv,void *p));
static int dombhostname __ARGS((int argc,char **argv,void *p));
static int dombescape __ARGS((int argc,char **argv,void *p));
#ifdef AX25
static int dombheard __ARGS((int argc,char **argv,void *p));
#endif
static int dodownload __ARGS((int argc,char **argv,void *p));
static int dombupload __ARGS((int argc,char **argv,void *p));
static int dombusermbx __ARGS((int argc,char **argv,void *p));
static int dowhat __ARGS((int argc,char **argv,void *p));
static int dosysop __ARGS((int argc,char **argv,void *p));
static int dostars __ARGS((int argc,char **argv,void *p));
static int dombhelp __ARGS((int argc,char **argv,void *p));
static int dogateway __ARGS((int argc,char **argv,void *p));
static int dombtelnet __ARGS((int argc,char **argv,void *p));
#ifdef CONVERS
static int dombconvers __ARGS((int argc,char **argv,void *p));
#endif
static int dombfinger __ARGS((int argc,char **argv,void *p));
#ifdef AX25
static int dombroute __ARGS((int argc,char **argv,void *p));
#endif
static int dombstat __ARGS((int argc,char **argv,void *p));
#ifdef NETROM
static int dombnrconnect __ARGS((int argc,char **argv,void *p));
static int dombnodes __ARGS((int argc,char **argv,void *p));
#endif
static int donothing __ARGS((int argc,char **argv,void *p));
static struct cmds near Mbcmds[] = {
"", donothing, 0, 0, NULLCHAR,
"bye ", domboxbye, 0, 0, NULLCHAR,
"bbs ", dombbs, 0, 0, NULLCHAR,
"chat", dogateway, 0, 0, NULLCHAR,
"connect", dogateway, 0, 0, NULLCHAR,
#ifdef CONVERS
"convers", dombconvers, 0, 0, NULLCHAR,
#endif
"download", dodownload, 0, 2, "d[u] file",
"escape", dombescape, 0, 0, NULLCHAR,
"exit", domboxbye, 0, 0, NULLCHAR,
"finger", dombfinger, 0, 0, NULLCHAR,
"help", dombhelp, 0, 0, NULLCHAR,
"info", dombhelp, 0, 0, NULLCHAR,
#ifdef AX25
"mheard", dombheard, 0, 0, NULLCHAR,
#endif
#ifdef NETROM
"nodes", dombnodes, 0, 0, NULLCHAR,
"nconnect", dombnrconnect, 0, 2, "nc call|node",
#endif
#ifdef AX25
"path", dombroute, 0, 0, NULLCHAR,
#endif
"quit", domboxbye, 0, 0, NULLCHAR,
"telnet", dombtelnet, 0, 2, "t host",
"user", dombusermbx, 0, 0, NULLCHAR,
"upload", dombupload, 0, 2, "u file",
"what", dowhat, 0, 0, NULLCHAR,
"? ", dombhelp, 0, 0, NULLCHAR,
/* cmds down here are not displayed by the "?" cmd */
"os", dombstat, 0, 0, NULLCHAR,
"@", dosysop, 0, 0, NULLCHAR,
"xr", dombhostname, 0, 0, NULLCHAR,
"***", dostars, 0, 0, NULLCHAR,
NULLCHAR, NULLFP, 0, 0, "\n*** Error?\n",
};
static int
donothing(int argc,char **argv,void *p)
{
return 0;
}
static void near
exitbbs(struct mbx *m)
{
struct mbx *mcp, *mclast = NULLMBX;
for(mcp = Mbox; mcp != NULLMBX; mclast = mcp, mcp = mcp->next) {
if(mcp == m) {
break;
}
}
if(mcp == NULLMBX) {
return; /* Not found */
}
/* Remove from list */
if(mclast != NULLMBX) {
mclast->next = mcp->next;
} else {
Mbox = mcp->next;
}
if(m->path != NULLCHAR) {
xfree(m->path);
}
if(m->startmsg != NULLCHAR) {
xfree(m->startmsg);
}
xfree(m->line);
xfree(m);
}
/* Incoming mailbox session */
void
mbx_incom(int s,void *t,void *p)
{
struct mbx *m;
#ifdef notused
struct usock *up;
#endif
int rval;
char *cp, buf2[MAXPATH];
FILE *fp;
sockowner(s,Curproc); /* We own it now */
sockmode(s,SOCK_ASCII);
close_s(Curproc->output);
close_s(Curproc->input);
Curproc->output = Curproc->input = s;
m = mxallocw(sizeof(struct mbx));
m->next = Mbox;
Mbox = m;
m->user = s;
setflush(m->user,-1);
m->escape = 24; /* default escape character is Ctrl-X */
m->type = (int)t;
m->line = mxallocw(LINELEN);
/* get the name of the remote station */
if(mbx_getname(m) == -1) {
goto quit;
}
m->state = MBX_CMD; /* start in command state */
if(userlogin(9980,0,m->name)) {
usputs(m->user,Banner);
usflush(m->user);
pause(5000);
dombbs(0x10,0,m);
goto quit;
}
#ifdef NETROM
if(Nrifaces[0].alias != NULLCHAR) {
cp = strxdup(Nrifaces[0].alias);
if((cp1 = strchr(cp,' ')) != NULLCHAR)
*cp1 = '\0';
sprintf(mbnrid,"%s:%s> ",cp,pax25(m->line,Nrifaces[0].iface->hwaddr));
xfree(cp);
} else {
mbnrid[0] = '\0';
}
#endif
sprintf(MBHostname,"%.28s",Hostname);
if((cp = strchr(MBHostname,'.')) != NULLCHAR) {
*cp = '\0';
}
strlwr(MBHostname);
/* Now say hi */
usprintf(m->user,Mbbanner,Banner,Hostname);
sprintf(buf2,"%s/host.hlp",EtcRoot);
if((fp = Fopen(buf2,READ_TEXT,0,0)) != NULLFILE) {
usputs(m->user,"\n");
sendfile(fp,m->user,ASCII_TYPE,0x80);
} else {
usputs(m->user," Type '?' for help.\n");
}
if(MMotd != NULLCHAR) {
usprintf(m->user,"%s\n",MMotd);
}
usprintf(m->user,"%s>\n",MBHostname);
while(mbxrecvline(m) != EOF) {
if((rval = mbx_parse(m)) == -2) {
break;
}
if(rval == 1) {
usputs(m->user,"Bad syntax\n");
}
usprintf(m->user,"%s>",MBHostname);
m->state = MBX_CMD;
}
quit:
exitbbs(m);
#ifdef notused
/* nasty hack! we may have screwed up reference count */
/* by invoking newproc("smtp_send",....); Fudge it! */
if((up = itop(Curproc->output)) != NULLUSOCK) {
up->refcnt = 1;
}
#endif
close_s(Curproc->output);
}
/* "twocmds" defines the MBL/RLI two-letter commands, eg. "SB", "SP" and so on.
* They have to be treated specially since cmdparse() wants a space between
* the actual command and its arguments.
* "SP FOO" is converted to "s foo" and the second command letter is saved
* in m->stype. Longer commands like "SEND" are unaffected, except for
* commands starting with "[", i.e. the SID, since we don't know what it will
* look like.
*/
static int near
mbx_parse(struct mbx *m)
{
int i;
char *cp, *newargv[2], twocmds[] = "d["; /* D is a two-letter command */
/* Translate entire buffer to lower case */
strlwr(m->line);
/* Skip any spaces at the begining */
for(cp = m->line; isspace(*cp); ++cp) ;
m->stype = ' ';
if(*cp != '\0' && *(cp+1) != '\0')
for(i = 0; i < strlen(twocmds); ++i) {
if(*cp == twocmds[i]
&& (isspace(*(cp+2)) || *(cp+2) == '\0' || *cp == '[')) {
m->stype = toupper(*++cp); /* Save the second character */
*cp = ' ';
break;
}
}
/* See if the input line consists solely of digits */
for(cp = m->line; isspace(*cp); ++cp) ;
newargv[1] = cp;
for( ; *cp != '\0' && isdigit(*cp); ++cp) ;
if(*cp == '\0' && strlen(newargv[1]) > 0) {
return 0;
} else {
log(m->user,9981,m->line); /* TEST */
i = cmdparse(Mbcmds,m->line,(void *)m);
switch(i) {
case -3:
usputs(m->user,Noperm);
return 0;
case -2:
return -2;
case -1:
return (m->err_cnt++ >= MAX_MBXERR) ? -2 : -1;
default:
m->err_cnt = 0;
return i;
}
}
}
static int near
mbx_getname(struct mbx *m)
{
union sp sp;
char *cp, tmp[MAXSOCKSIZE];
int oldmode, len = MAXSOCKSIZE;
sp.p = tmp;
sp.sa->sa_family = AF_LOCAL; /* default to AF_LOCAL */
getpeername(m->user,tmp,&len);
m->family = sp.sa->sa_family;
/* This is one of the two parts of the mbox code that depends on the
* underlying protocol. We have to figure out the name of the
* calling station. This is only practical when AX.25 or NET/ROM is
* used. Telnet users have to identify themselves by a login procedure.
*/
switch(m->family){
#ifdef AX25
case AF_NETROM:
case AF_AX25:
/* NETROM and AX25 socket address structures are "compatible" */
addrcp(m->nodename,sp.ax->ax25_addr);
m->nodename[ALEN] ^= 0x1e;
pax25(m->name,sp.ax->ax25_addr);
if((cp = strchr(m->name,'-')) != NULLCHAR)
*cp = '\0';
break;
#endif
default:
m->state = MBX_LOGIN;
usprintf(m->user,Loginbanner,Hostname);
for(;;){
usputs(m->user,"Login (Call): ");
if(mbxrecvline(m) == EOF) {
return -1;
}
if(*m->line == '\0') {
continue;
}
cp = m->line;
while(isspace(*cp)) {
cp++;
}
sprintf(m->name,"%.19s",cp);
#ifdef AX25
if(setcall(m->nodename,m->name) == -1)
addrcp(m->nodename,Mycall);
m->nodename[ALEN] ^= 0x1e;
#else
m->nodename[0] = '\0';
#endif
usprintf(m->user,"Password: %c%c%c",IAC,WILL,TN_ECHO);
oldmode = sockmode(m->user,SOCK_BINARY);
if(mbxrecvline(m) == EOF) {
return -1;
}
usprintf(m->user,"%c%c%c",IAC,WONT,TN_ECHO);
sockmode(m->user,oldmode);
usputs(m->user,"\n");
usflush(m->user);
/* This is needed if the password was send before the
* telnet no-echo options were receied. We neeed to
* flush the eold sequence from the input buffers, sigh
*/
if(socklen(m->user,0)) { /* discard any remaining input */
recv_mbuf(m->user,NULL,0,NULLCHAR,0);
}
break;
}
break;
}
/* Try to find the privileges of this user from the userfile */
userlogin(IPPORT_TELNET,(void *)m,m->line);
log(m->user,9983,"NODE open %s %s",m->name,m->perms ? "" : m->line);
/* SMTP wants the name to be in lower case */
strlwr(m->name);
return (m->perms & EXCLUDED_CMD) ? -1 : 0;
}
/* This works like recvline(), but telnet options are answered and the
* terminating newline character is not put into the buffer. If the
* incoming character equals the value of escape, any queued input is
* flushed and -2 returned.
*/
int
mbxrecvline(struct mbx *m)
{
int c, cnt = 0, opt;
char *buf = m->line;
usflush(m->user);
while((c = recvchar(m->user)) != -1) {
if(c == IAC) { /* Telnet command escape */
if((c = recvchar(m->user)) == -1) {
break;
}
if(c > 250 && c < 255 && (opt = recvchar(m->user)) != -1) {
#ifdef XXX
switch(c) {
case WILL:
usprintf(m->user,"%c%c%c",IAC,DONT,opt);
break;
case WONT:
usprintf(m->user,"%c%c%c",IAC,DONT,opt);
break;
case DO:
usprintf(m->user,"%c%c%c",IAC,WONT,opt);
break;
case DONT:
usprintf(m->user,"%c%c%c",IAC,WONT,opt);
}
usflush(m->user);
#endif
continue;
}
if(c != IAC && opt == -1) {
break;
}
}
/* ordinary character */
if(c == '\r' || c == '\n') {
break;
}
if(c == m->escape) {
if(socklen(m->user,0)) { /* discard any remaining input */
recv_mbuf(m->user,NULL,0,NULLCHAR,0);
}
cnt = -2;
break;
}
*buf++ = c;
if(++cnt > LINELEN - 2) {
break;
}
}
if(c == -1 && cnt == 0) {
return -1;
}
*buf = '\0';
return cnt;
}
static int
domboxbye(int argc,char **argv,void *p)
{
struct mbx *m = (struct mbx *) p;
/* Now say goodbye */
usputs(m->user,"73!\n");
usflush(m->user);
usflush(Curproc->output);
log(m->user,9983,"NODE close");
return -2; /* signal that exitbbs() should be called */
}
static int
dombhelp(int argc,char **argv,void *p)
{
struct mbx *m = (struct mbx *) p;
if(argc < 2) {
int i;
struct cmds *cmdp;
usputs(m->user,"\nAvailable commands:\n");
for(i = 0, cmdp = Mbcmds; cmdp->name != NULLCHAR; cmdp++) {
if(strlen(cmdp->name) > 3) {
usprintf(m->user,"%-15.15s%s",cmdp->name,(i == 4) ? "\n" : "");
i = (i + 1) % 5;
}
}
if(i) {
usputs(m->user,"\n");
}
} else {
gethelp(9981,m->user,argv[1]);
}
return 0;
}
#ifdef AX25
static int
dombroute(int argc,char **argv,void *p)
{
if( argc < 2) {
struct mbx *m = (struct mbx *)p;
struct axroute_tab *rp;
int k = 0;
char tmp[AXBUF];
usputs(m->user,"Destinations:\n");
for(rp = Axroute_tab; rp; rp = rp->next) {
pax25(tmp,(char *)&rp->call);
usprintf(m->user,(k++ % 4) < 3 ? "%-20.19s" : "%s\n",tmp);
}
if(k % 4) {
usputs(m->user,"\n");
}
} else {
doroutelist(argc,argv,p);
}
return 0;
}
#endif
static int
dombstat(int argc,char **argv,void *p)
{
dostatus(9,0,p);
return 0;
}
static int
dombescape(int argc,char **argv,void *p)
{
struct mbx *m = (struct mbx *)p;
if(argc < 2){
usprintf(m->user,"The escape character is: CTRL-%c\n",m->escape+'A'-1);
return 0;
}
if(iscntrl(*argv[1])) {
m->escape = *argv[1];
return 0;
}
return 1;
}
static int
dodownload(int argc,char **argv,void *p)
{
struct mbx *m = (struct mbx *)p;
char *file = pathname(m->path,argv[1]);
if(!permcheck(m->path,m->perms,RETR_CMD,file)) {
xfree(file);
return -3;
} else {
FILE *fp;
if(m->stype == 'U') {
if((fp = Fopen(file,READ_BINARY,m->user,0)) != NULLFILE) {
/* uuencode a file -- translated from C++; both versions copyright 1990
* by David R. Evans, G4AMJ/NQ0I
*/
int n_read_so_far = 0, n_written_so_far = 0, in_chars, n, mode = 0755;
unsigned long cnt = 0;
static unsigned char in[3], out[4], line[100];
usprintf(m->user,"\nbegin %03o %s\n",mode,argv[1]);
/* do the encode */
while((in_chars = fread(in,1,3,fp)) != 0) {
out[0] = in[0] >> 2;
out[1] = in[0] << 6;
out[1] = out[1] >> 2;
out[1] = out[1] | (in[1] >> 4);
out[2] = in[1] << 4;
out[2] = out[2] >> 2;
out[2] = out[2] | (in[2] >> 6);
out[3] = in[2] << 2;
out[3] = out[3] >> 2;
for (n = 0; n < 4; n++) {
out[n] += ' ';
}
n_read_so_far += in_chars;
for (n = 0; n < 4; n++) {
line[n_written_so_far++] = out[n];
}
if ((in_chars != 3) || (n_written_so_far >= 60)) {
line[(n_read_so_far + 2) / 3 * 4] = '\0';
if(usprintf(m->user,"%c%s\n",n_read_so_far + ' ', line) == EOF) {
goto quit;
}
usflush(m->user);
cnt += n_read_so_far;
n_read_so_far = 0;
n_written_so_far = 0;
}
}
usprintf(m->user," \nend\nsize %lu\n\n",cnt);
quit:
Fclose(fp);
}
} else {
if((fp = Fopen(file,READ_TEXT,m->user,0)) != NULLFILE) {
sendfile(fp,m->user,ASCII_TYPE,0x80);
}
}
}
xfree(file);
return 0;
}
static int near
mbuser(int socket)
{
int len, s;
char *cp, *cp1, fsocket[MAXSOCKSIZE], upl[40], down[40];
struct usock *up, *up1;
struct mbx *m;
#ifdef AX25
char tmp[AXBUF];
#endif
#ifdef NETROM
struct nrroute_tab *np;
char temp[AXBUF], *cp2, *cp3;
char circuit[] = "Circuit (%s%s %s)";
#endif
usputs(socket,"User:\n");
for(m = Mbox; m != NULLMBX; m = m->next) {
len = MAXSOCKSIZE;
getpeername(m->user,fsocket,&len);
cp = strxdup(psocket(fsocket));
*upl = '\0';
*down = '\0';
switch(m->family) { /* UPLINK */
#ifdef AX25
case AF_AX25:
if((cp1 = strchr(cp,' ')) != NULLCHAR) {
*cp1 = '\0';
}
sprintf(upl,"Uplink (%s)",cp);
break;
#endif
#ifdef NETROM
case AF_NETROM:
if((cp1 = strchr(cp,' ')) != NULLCHAR) {
*cp1 = '\0';
}
cp1 += 3;
setcall(temp,cp1);
if((np = find_nrroute(temp)) != NULLNRRTAB) {
cp2 = strxdup(np->alias);
} else {
cp2 = "";
}
if((cp3 = strchr(cp2,' ')) != NULLCHAR) {
*cp3 = '\0';
}
if(isalnum(*cp2)) {
strcat(cp2,":");
} else {
*cp2 = '\0';
}
sprintf(upl,circuit,cp2,cp1,cp);
xfree(cp2);
break;
#endif
case AF_INET:
if((cp1 = strchr(cp,':')) != NULLCHAR) {
*cp1 = '\0';
}
sprintf(upl,"Telnet (%s)",cp);
break;
default:
strcpy(upl,"Connect");
break;
}
xfree(cp);
usprintf(socket,"%-36s",upl);
for(s = SOCKBASE; s < Nusock + SOCKBASE; s++) {
if((up = itop(s)) == NULLUSOCK || s == m->user) {
continue;
}
up1 = itop(m->user);
if(up->owner == up1->owner) {
getpeername(s,fsocket,&len);
cp = strxdup(psocket(fsocket));
switch(up->type) {
case TYPE_TCP:
if((cp1 = strchr(cp,':')) != NULLCHAR) {
*cp1 = '\0';
}
sprintf(down,"Telnet (%s)",cp);
break;
#ifdef AX25
case TYPE_AX25I:
if((cp1 = strchr(cp,' ')) != NULLCHAR) {
*cp1 = '\0';
}
sprintf(down,"Downlink (%s %s)",pax25(tmp,m->nodename),cp);
break;
#endif
#ifdef NETROM
case TYPE_NETROML4:
if((cp1 = strchr(cp,' ')) != NULLCHAR) {
*cp1 = '\0';
}
cp1 += 3;
setcall(temp,cp1);
np = find_nrroute(temp);
cp2 = strxdup(np->alias);
if((cp3 = strchr(cp2,' ')) != NULLCHAR) {
*cp3 = '\0';
}
addrcp(cp,m->nodename);
cp[ALEN] ^= 0x1e;
if(isalnum(*cp2)) {
strcat(cp2,":");
} else {
*cp2 = '\0';
}
sprintf(down,circuit,cp2,cp1,pax25(temp,cp));
xfree(cp2);
break;
#endif
default:
strcpy(down,"Connect");
break;
}
xfree(cp);
usprintf(socket,"<--> %s",down);
break;
}
}
usputs(socket,"\n");
}
return 0;
}
static int
dombusermbx(int argc,char **argv,void *p)
{
struct mbx *m = (struct mbx *)p;
#ifdef NETROM
if(m->family == AF_NETROM) {
usputs(m->user,mbnrid);
}
#endif
return mbuser(m->user);
}
static int
dombupload(int argc,char **argv,void *p)
{
FILE *fp;
struct mbx *m = (struct mbx *)p;
char *file = pathname(m->path,argv[1]);
if(!permcheck(m->path,m->perms,STOR_CMD,file)) {
xfree(file);
return -3;
} else if((fp = Fopen(file,WRITE_TEXT,m->user,1)) != NULLFILE) {
usprintf(m->user,"Send file. %s",Howtoend);
for(;;) {
if(mbxrecvline(m) == EOF) {
break;
}
if(*m->line == 0x01){ /* CTRL-A */
unlink(file);
usputs(m->user,Aborted);
break;
}
if(*m->line == CTLZ
|| !stricmp(m->line,"/ex")
|| !stricmp(m->line,"***end")
|| !strcmp(m->line,".")) {
break;
}
fprintf(fp,"%s\n",m->line);
}
Fclose(fp);
}
xfree(file);
return 0;
}
static int
dowhat(int argc,char **argv,void *p)
{
FILE *fp;
char *file;
struct mbx *m = (struct mbx *)p;
if(argc < 2) {
file = strxdup(m->path);
} else {
file = pathname(m->path,argv[1]);
}
if(!permcheck(m->path,m->perms,RETR_CMD,file)) {
xfree(file);
return -3;
} else if((fp = dir(file,1)) != NULLFILE) {
sendfile(fp,m->user,ASCII_TYPE,0x80);
}
xfree(file);
return 0;
}
int
dosysopset(int argc,char **argv,void *p)
{
if(strlen(argv[1]) == 5 && atol(argv[1]) != 0) {
strcpy(number,argv[1]);
}
return 0;
}
static int
dosysop(int argc,char **argv,void *p)
{
int c, i, k;
unsigned long int digit1[25], digit;
struct mbx *m = (struct mbx *) p;
if(!(m->perms & SYSOP_CMD)) {
return -3;
}
for(i=0; i<15; i++) {
digit1[i] = random(10);
usprintf(m->user,"%d",digit1[i]);
if(i == 4 || i == 9)
usputs(m->user,", ");
}
usputs(m->user,">");
c = mbxrecvline(m);
if(c == EOF || c == -2)
return 0;
if((digit = atol(number)) == 0)
digit = 22222;
digit1[15] = digit/10000;
digit -= digit1[15]*10000;
digit1[16] = digit/1000;
digit -= digit1[16]*1000;
digit1[17] = digit/100;
digit -= digit1[17]*100;
digit1[18] = digit/10;
digit -= digit1[18]*10;
digit1[19] = digit;
for(i=0; i<3; i++) {
digit1[i+20] = 0;
for(k=0; k<5; k++)
digit1[i+20] += digit1[k+i*5] * digit1[k+15];
}
rip(m->line);
if((digit = atol(m->line)) != 0
&& (digit == digit1[20] || digit == digit1[21] || digit == digit1[22])) {
for(;;) {
usputs(m->user,"Net> ");
c = mbxrecvline(m);
if(c == EOF || c == -2)
break;
log(m->user,9981,"SYSOP mode: %s",m->line);
cmdparse(Cmds,m->line,NULL);
}
return 0;
} else
return -3;
}
static int
dostars(int argc,char **argv,void *p)
{
if(strcmp(argv[1],"error?") == 0) {
return -2;
}
return -1;
}
#ifdef AX25
static int
dogateway(int argc,char **argv,void *p)
{
extern int Attended;
struct mbx *m = (struct mbx *)p;
struct sockaddr_ax fsocket, lsocket;
int s;
char *ap, path[10*AXALEN+1];
struct iface *ifp = NULLIF;
struct ax25_cb axp;
if(argc < 2) {
if(Attended || (!Attended && *MHostname)) {
char buf[5], *newargv[3];
newargv[0] = "telnet";
newargv[1] = (*MHostname) ? MHostname : Hostname;
sprintf(buf,"%d",IPPORT_TTYLINK);
newargv[2] = buf;
return dombtelnet(3,newargv,p);
} else {
char *name = strxdup(MBHostname);
strlwr(name);
usprintf(m->user,"OP is absent, pse enter the BBS and leave msg with 's %s'\n",name);
xfree(name);
return 0;
}
}
if(!(m->perms & AX25_CMD)) {
return -3;
}
argc--;
argv++;
if((ifp = if_lookup(*argv)) != NULLIF) {
if(ifp->output != ax_output) {
usprintf(m->user,Badax,*argv);
return 0;
}
argc--;
argv++;
}
for(ap = path; argc > 0; argc--, argv++) {
if(!strncmp("via", *argv, strlen(*argv))) {
continue;
}
if(ap > path + sizeof(path) - 1) {
usputs(m->user,"Max 8 digis\n");
return 0;
}
if(setcall(ap, *argv)) {
usprintf(m->user,Invcall,*argv);
return 0;
}
ap[ALEN] &= ~E;
if(ap == path) {
ap += AXALEN;
addrcp(ap,Mycall);
ap[ALEN] &= ~E;
}
ap += AXALEN;
}
if(ap < path + 2 * AXALEN) {
usputs(m->user,"Missing call\n");
return 0;
}
ap[-1] |= E;
memset(&axp,0,sizeof(struct ax25_cb));
build_path(&axp,ifp,path,0);
if(!axp.iface) {
usputs(m->user,"No specified iface\n");
return 0;
}
if(callreq(axp.path)) {
char tmp[AXBUF];
usprintf(m->user,Invcall,pax25(tmp,axp.path));
return 0;
}
addrcp(axp.path + AXALEN,axp.iface->hwaddr);
axroute_add(&axp,0);
if((s = socket(AF_AX25,SOCK_STREAM,0)) == -1){
usputs(m->user,Nosocket);
return 0;
}
fsocket.sax_family = AF_AX25;
addrcp(fsocket.ax25_addr,axp.path);
memcpy(fsocket.iface,axp.iface->name,ILEN);
m->startmsg = NULLCHAR;
lsocket.sax_family = AF_AX25;
addrcp(lsocket.ax25_addr,(*m->name == '\0') ? axp.iface->hwaddr : m->nodename);
bind(s,(char *)&lsocket,SOCKSIZE);
return gw_connect(m,s,(char *)&fsocket,SOCKSIZE);
}
#else
static int
dogateway(int argc,char **argv,void *p)
{
extern int Attended;
struct mbx *m = (struct mbx *) p;
if(argc < 2) {
if(Attended) {
char buf[5], *newargv[3];
newargv[0] = "telnet";
newargv[1] = Hostname;
sprintf(buf,"%d",IPPORT_TTYLINK);
newargv[2] = buf;
return dombtelnet(3,newargv,p);
} else {
char *name = strxdup(MBHostname);
strlwr(name);
usprintf(m->user,"OP is absent, pse enter the BBS and leave msg with 's %s'\n",name);
xfree(name);
return 0;
}
}
usputs(m->user,Noserv);
return 0;
}
#endif
static int
dombtelnet(int argc,char **argv,void *p)
{
int s, len, i;
char dsocket[MAXSOCKSIZE];
struct sockaddr_in fsocket;
struct mbx *m = (struct mbx *) p;
fsocket.sin_family = AF_INET;
fsocket.sin_port = (argc < 3) ? IPPORT_TELNET : atoi(argv[2]);
if((fsocket.sin_addr.s_addr = resolve(argv[1])) == 0){
usprintf(m->user,Badhost,argv[1]);
return 0;
}
/* Only local telnets are are allowed to the unprivileged user */
if(!(m->perms & TELNET_CMD) && !ismyaddr(fsocket.sin_addr.s_addr))
return -3;
if((s = socket(AF_INET,SOCK_STREAM,0)) == -1){
usputs(m->user,Nosocket);
return 0;
}
switch(fsocket.sin_port) {
case IPPORT_TTYLINK:
m->startmsg = mxallocw(80);
len = MAXSOCKSIZE;
i = getpeername(m->user,dsocket,&len);
sprintf(m->startmsg,"*** Incoming call from %s@%s ***\n",
m->name,(i != -1) ? psocket(dsocket) : Hostname);
break;
#ifdef CONVERS
case IPPORT_CONVERS:
/*
if(m->startmsg == NULLCHAR) {
m->startmsg = mxallocw(40);
sprintf(m->startmsg,
"/n %s %d\n",m->name,(argc > 3) ? atoi(argv[3]) : 0);
}
*/
m->state = MBX_CONVERS;
break;
#endif
}
return gw_connect(m,s,(char *)&fsocket,SOCKSIZE);
}
static int
dombfinger(int argc,char **argv,void *p)
{
struct mbx *m = (struct mbx *)p;
char *host, *user = NULLCHAR, buf[8], *newargv[3];
if(argc > 2) {
usputs(m->user,"Usage: finger <user[@host]|@host>\n");
return 0;
}
host = Hostname;
if(argc == 2) {
if((host = strchr(argv[1], '@')) != NULLCHAR) {
*host = '\0';
host++;
} else {
host = Hostname;
}
user = argv[1];
}
m->startmsg = mxallocw(80);
sprintf(m->startmsg,"%s\n",user ? user : "");
newargv[0] = "telnet";
newargv[1] = host;
sprintf(buf,"%d",IPPORT_FINGER);
newargv[2] = buf;
return dombtelnet(3,newargv,p);
}
#ifdef CONVERS
static int
dombconvers(int argc,char **argv,void *p)
{
char *newargv[3], buf[6];
newargv[0] = "telnet";
newargv[1] = Hostname;
sprintf(buf,"%d",IPPORT_CONVERS);
newargv[2] = buf;
return dombtelnet(3,newargv,p);
}
#endif
/* Generic mbox gateway code. It sends and frees the contents of m->startmsg
* when the connection has been established unless it a null pointer.
*/
static int near
gw_connect(struct mbx *m,int s,char *fsocket,int len)
{
int c;
char *cp, *cp1, *node, buf[80];
struct gwalarm *gwa;
struct proc *child = newproc("gw supervisor",256,gw_superv,0,Curproc,m,0);
sockmode(s,SOCK_ASCII);
if(m->family == AF_AX25) {
usputs(m->user,"link setup...\n");
usflush(m->user);
}
node = strxdup(psocket((struct sockaddr *)fsocket));
if((cp1 = strchr(node,' ')) != NULLCHAR)
*cp1 = '\0';
if(connect(s,fsocket,len) == -1) {
if((cp = sockerr(s)) != NULLCHAR) {
switch(cp[0]) {
case 'R':
#ifdef NETROM
sprintf(buf,"%susy from",
(m->family == AF_NETROM) ? "B" : "*** b");
#else
sprintf(buf,"*** busy from");
#endif
break;
case 'T':
if(m->family != AF_NETROM) {
sprintf(buf,"*** timeout with");
break;
}
default:
#ifdef NETROM
sprintf(buf,"%sailure with",
(m->family == AF_NETROM) ? "F" : "*** f");
#else
sprintf(buf,"*** failure with");
#endif
break;
}
#ifdef NETROM
if(m->family == AF_NETROM)
usputs(m->user,mbnrid);
#endif
usprintf(m->user,"%s %s\n",buf,node);
}
xfree(m->startmsg);
m->startmsg = NULLCHAR;
xfree(node);
killproc(child);
close_s(s);
return 0;
}
/* log(Curproc->input,9981,"connect %s",node); */
#ifdef NETROM
if(m->family == AF_NETROM)
usputs(m->user,mbnrid);
usprintf(m->user,"%sonnected to %s\n",
(m->family == AF_NETROM) ? "C" : "*** c", node);
#else
usprintf(m->user,"*** connected to %s\n",node);
#endif
xfree(node);
/* The user did not type the escape character */
killproc(child);
if(m->startmsg != NULLCHAR) {
usputs(s,m->startmsg);
xfree(m->startmsg);
m->startmsg = NULLCHAR;
}
/* Since NOS does not flush the output socket after a certain
* period of time, we have to arrange that ourselves.
*/
gwa = mxallocw(sizeof(struct gwalarm));
stop_timer(&gwa->t);
gwa->s1 = Curproc->output;
gwa->s2 = s;
gwa->t.func = gw_alarm;
gwa->t.arg = gwa;
set_timer(&gwa->t,240); /* DB3FL */
start_timer(&gwa->t);
/* Fork off the receive process */
child = newproc("gw in",1024,gw_input,s,m,Curproc,0);
for(;;) {
if((c = recvchar(Curproc->input)) == -1)
break;
if(c == m->escape) {
if(socklen(Curproc->input,0)) {
recv_mbuf(Curproc->input,NULL,0,NULLCHAR,0);
}
break;
}
if(usputc(s,c) == EOF)
break;
}
stop_timer(&gwa->t);
xfree(gwa);
close_s(s);
killproc(child); /* get rid of the receive process */
if(m->family == AF_INET || m->family == AF_LOCAL) {
usprintf(m->user,"%c%c%c\n",IAC,WONT,TN_ECHO);
}
return 0;
}
static void
gw_input(int s,void *notused,void *p)
{
int c;
char *cp;
struct proc *parent = (struct proc *)p;
struct mbx *m = (struct mbx *)notused;
while((c = recvchar(s)) != EOF) {
usputc(m->user,c);
}
if((cp = sockerr(s)) != NULLCHAR && m->family != AF_NETROM) {
switch(*cp) {
case 'T':
usprintf(m->user,"\n*** %s: Link failure",MBHostname);
break;
case 'R':
usputs(m->user,"*** DM received");
break;
}
}
#ifdef NETROM
if(m->family == AF_NETROM)
usputs(m->user,mbnrid);
#endif
usprintf(m->user,"\n%seconnected to %s\n",
#ifdef NETROM
(m->family == AF_NETROM) ? "R" :
#endif
"*** r",MBHostname);
/* Tell the parent that we are no longer connected */
alert(parent,(void *)ENOTCONN);
pwait(Curproc); /* Now wait to be killed */
}
/* Check if the escape character is typed while the parent process is busy
* doing other things.
*/
static void
gw_superv(int null,void *proc,void *p)
{
int c;
struct proc *parent = (struct proc *) proc;
struct mbx *m = (struct mbx *) p;
while((c = recvchar(Curproc->input)) != EOF)
if(c == m->escape){
/* flush anything in the input queue */
if(socklen(Curproc->input,0))
recv_mbuf(Curproc->input,NULL,0,NULLCHAR,0);
break;
}
alert(parent,(void *)EINTR); /* Tell the parent to quit */
pwait(Curproc); /* Please kill me */
}
static void
gw_alarm(void *p)
{
char oldbl;
struct usock *up;
struct gwalarm *gwa = (struct gwalarm *)p;
/* Flush sockets s1 and s2, but first make sure that the socket
* is set to non-blocking mode, to prevent the flush from blocking
* if the high water mark has been reached.
*/
if((up = itop(gwa->s1)) != NULLUSOCK) {
oldbl = up->noblock;
up->noblock = 1;
usflush(gwa->s1);
up->noblock = oldbl;
}
if((up = itop(gwa->s2)) != NULLUSOCK) {
oldbl = up->noblock;
up->noblock = 1;
usflush(gwa->s2);
up->noblock = oldbl;
}
start_timer(&gwa->t);
}
#ifdef AX25
static int
dombheard(int argc,char **argv,void *p)
{
return doaxheard(argc,argv,p);
}
#endif
#ifdef NETROM
static int
dombnodes(int argc,char **argv,void *p)
{
int k = -1;
struct mbx *m = (struct mbx *) p;
if(!(m->perms & NETROM_CMD))
return -3;
if(Nrifaces[0].alias == NULLCHAR) {
usputs(m->user,Noserv);
return 0;
}
if(argc == 2)
k = 9;
if(argc > 1) {
if(stricmp(argv[1],"tcp") == 0)
k = 0;
if(*argv[1] == '*')
k = 10;
}
if(k != -1) {
usprintf(m->user,"%sNodes:\n",(m->family == AF_NETROM) ? mbnrid : "");
return doroutedump(k,0,p);
}
if(dorouteinfo(9,argv,p) == -1) {
usprintf(m->user,"%s%so route to %s\n",
(m->family == AF_NETROM) ? mbnrid : "",
(m->family == AF_NETROM) ? "N" : "*** n",
strupr(argv[1]));
return -1;
}
return 0;
}
static int
dombnrconnect(int argc,char **argv,void *p)
{
int s;
struct sockaddr_nr lsocket, fsocket;
char *np, alias[AXBUF];
struct mbx *m = (struct mbx *) p;
if((s = socket(AF_NETROM,SOCK_SEQPACKET,0)) == -1){
usputs(m->user,Nosocket);
return 0;
}
lsocket.nr_family = AF_NETROM;
/* Set up our local username, bind would use Mycall instead */
addrcp(lsocket.nr_addr.user,m->nodename);
lsocket.nr_addr.user[ALEN] ^= 0x1e;
/* Putting anything else than Mycall here will not work */
addrcp(lsocket.nr_addr.node,Mycall);
bind(s,(char *)&lsocket,SOCKSIZE);
/* See if the requested destination could be an alias, and
* find and use it if it is. Otherwise assume it is an ax.25
* address.
*/
if(putalias(alias,argv[1],0) != -1 &&
(np = find_nralias(alias)) != NULLCHAR){
addrcp(fsocket.nr_addr.user,np);
addrcp(fsocket.nr_addr.node,np);
} else { /* parse ax25 callsign */
/* Only the user callsign of the remote station is never used by */
/* NET/ROM, but it is needed for the psocket() call. */
setcall(fsocket.nr_addr.user,argv[1]);
setcall(fsocket.nr_addr.node,argv[1]);
}
fsocket.nr_family = AF_NETROM;
return gw_connect(m,s,(char *)&fsocket,SOCKSIZE);
}
#endif
/* ---------------------------- Mbox subcmds ------------------------------ */
/* ------------------------------- begin ---------------------------------- */
static int
dombmotd(int argc,char **argv,void *p)
{
if(argc < 2) {
if(MMotd[0] != '\0')
tputs(MMotd);
} else {
int i;
*MMotd = '\0';
for(i = 1; i < argc; i++) {
strcat(MMotd,argv[i]);
if(strlen(MMotd) > 110) {
break;
}
strcat(MMotd," ");
}
if(strlen(MMotd) > 2) {
strcat(MMotd,"\n\0");
} else {
*MMotd = '\0';
}
}
return 0;
}
static int
dombhostname(int argc,char **argv,void *p)
{
struct mbx *m = (struct mbx *)p;
if(*argv[0] == 'x') {
if(!(m->perms & SYSOP_CMD)) {
return -3;
}
}
if(argc < 2) {
if(*MHostname != '\0') {
tprintf("%s\n",MHostname);
}
} else {
sprintf(MHostname,"%.27s",argv[1]);
}
return 0;
}
static int
domboxdisplay(int argc,char **argv,void *p)
{
struct mbx *m;
static char fsocket[MAXSOCKSIZE], *states[] =
{"LOGIN","CMD","BBS","CONVERS"};
tputs("User State S# Where\n");
for(m = Mbox; m != NULLMBX; m = m->next) {
int len = MAXSOCKSIZE;
int j = getpeername(m->user,fsocket,&len);
tprintf("%-11s%-9s%-4u%s\n",
m->name,
states[m->state],
m->user,
(j != -1) ? psocket(&fsocket) : "");
}
return 0;
}
#ifdef UK
/* if ThirdParty is not set - restrict the mailbox (S)end command to local only */
int
dombthirdparty(int argc,char **argv,void *p)
{
return setbool(&ThirdParty,"Third-Party Mail",argc,argv);
}
#endif
#ifdef MODEM
static int
dotimeout(int argc,char **argv,void *p)
{
return setuns(&Tiptimeout,"Tip conn timeout",argc,argv);
}
#endif
static int
dombusercon(int argc,char **argv,void *p)
{
return mbuser(Curproc->output);
}
int
dombox(int argc,char **argv,void *p)
{
/* mbox subcommand table */
struct cmds Mbxsubcmd[] = {
#ifdef AX25
"finfo", dofinfo, 0, 0, NULLCHAR, /* in bbs.c */
"fkick", dofkick, 1024, 0, NULLCHAR, /* in bbs.c */
"fnic", dofnic, 0, 0, NULLCHAR, /* in bbs.c */
#endif
"motd", dombmotd, 0, 0, NULLCHAR,
"remote", dombhostname, 0, 0, NULLCHAR,
"status", domboxdisplay, 0, 0, NULLCHAR,
#ifdef UK
"thirdparty", dombthirdparty, 0, 0, NULLCHAR,
#endif
#ifdef MODEM
"tiptimeout", dotimeout, 0, 0, NULLCHAR,
#endif
"user", dombusercon, 0, 0, NULLCHAR,
NULLCHAR,
};
return subcmd(Mbxsubcmd,argc,argv,p);
}
/* -------------------------------- end ----------------------------------- */
/* ---------------------------- Mbox subcmds ------------------------------ */